//------------------------------------------------------------------------------ 
//  <copyright file="SourceReaderCallback.h" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//  </copyright>
//------------------------------------------------------------------------------
#pragma once

#include "Managed.h"

namespace Microsoft {
    namespace Robotics {
        namespace Vision {
            namespace Cameras {
				namespace Webcam {

    /// <summary>
    /// Read sample delegate which is called back for each image.
    /// </summary>
    /// <param name="data"> Image data as RGB24 byte array </param>
    /// <param name="cbLength"> Length of Image data in bytes </param>
    public delegate void ReadSampleDelegate(IntPtr data, int cbLength);

    /// <summary>
    /// CABI for read sample handler.
    /// </summary>
    /// <param name="data"> Image data as RGB24 byte array </param>
    /// <param name="cbLength"> Length of Image data in bytes </param>
    typedef void (__stdcall *ReadSampleHandlerForDevice)(BYTE* data, int cbLength);

    /// <summary>
    // Class used to represent a capture device which can receive asynchronous notifications.
    /// </summary>
    class SourceReaderCallback : public IMFSourceReaderCallback
    {
    public:
        /// <summary>
        // Creates an instance of the capture device which implements <c> IMFSourceReaderCallback </c>
        /// </summary>
        ///<param name="ppPlayer">The reference to the source reader to the created</param>
        ///<returns> S_OK if succeeded. Error code if not.</returns>
        static HRESULT CreateInstance(SourceReaderCallback **ppPlayer);

        // IUnknown methods

        /// <summary>
        // Retrieves pointers to the supported interfaces on an object
        /// </summary>
        ///<param name="ppv">The reference to interface to be retrieved</param>
        ///<returns> S_OK if succeeded. Error code if not.</returns>
        STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
        
        /// <summary>
        // Increments the reference count for an interface on an object
        /// </summary>
        ///<returns> The method returns the new reference count.</returns>
        STDMETHODIMP_(ULONG) AddRef();

        /// <summary>
        // Decrements the reference count for an interface on an object
        /// </summary>
        ///<returns> The method returns the new reference count.</returns>
        STDMETHODIMP_(ULONG) Release();

        // IMFSourceReaderCallback methods

        /// <summary>
        // Called when the IMFSourceReader::ReadSample method completes
        /// </summary>
        ///<param name="hrStatus">
        /// The status code. 
        /// If an error occurred while processing the next smple, this parameter contains the error code 
        /// </param>
        ///<param name="dwStreamIndex">The zero-based index of the stream that delivered the sample</param>
        ///<param name="dwStreamFlags">A bitwise OR of zero or more flags from the MF_SOURCE_READER_FLAG enumeration</param>
        ///<param name="llTimestamp">
        /// The time stamp of the sample, or the time of the stream event indicated in dwStreamFlags. 
        /// The time is given in 100-nanosecond units
        /// </param>
        ///<param name="pSample">A pointer to the IMFSample interface of a media sample. This parameter might be NULL.</param>
        ///<returns> S_OK if succeeded. Error code if not.</returns>
        STDMETHODIMP OnReadSample(
            _In_ HRESULT hrStatus,
            _In_ DWORD dwStreamIndex,
            _In_ DWORD dwStreamFlags,
            _In_ LONGLONG llTimestamp,
            _In_opt_ IMFSample *pSample);

        /// <summary>
        // Called when the source reader receives certain events from the media source
        /// </summary>
        ///<param name="dwStreamIndex">
        /// For stream events, the value is the zero-based index of the stream that sent the event. 
        /// For source events, the value is MF_SOURCE_READER_MEDIASOURCE
        /// </param>
        ///<param name="pEvent">A pointer to the IMFMediaEvent interface of the event </param>
        ///<returns> S_OK if succeeded. Error code if not.</returns>
        STDMETHODIMP OnEvent(_In_ DWORD dwStreamIndex, _In_ IMFMediaEvent *pEvent)
        {
            return S_OK;
        }

        /// <summary>
        // Called when the IMFSourceReader::Flush method completes
        /// </summary>
        ///<param name="dwStreamIndex">
        /// For stream events, the value is the zero-based index of the stream that sent the event. 
        /// For source events, the value is MF_SOURCE_READER_MEDIASOURCE
        /// </param>
        ///<returns> S_OK if succeeded. Error code if not.</returns>
        STDMETHODIMP OnFlush(DWORD dwStreamIndex)
        {
            return S_OK;
        }

        /// <summary>
        // Sets the video format.
        /// </summary>        
        ///<param name="width">Width in pixels </param>
        ///<param name="width">Height in pixels </param>
        void SetFormat(size_t width, size_t height)
        {
            m_width = width;
            m_height = height;
        }

        /// <summary>
        // Initiates capture sample
        /// </summary>        
        ///<param name="handler">The handler to call on read sample completion </param>
        void CaptureSample(ReadSampleHandlerForDevice handler);

        /// <summary>
        // Sets the source reader
        /// </summary>        
        ///<param name="pReader">The MF source reader being wrapped by this class</param>
        void SetSourceReader(IMFSourceReader *pReader)
        {
            m_pReader = pReader;
            m_pReader->AddRef();
        }

    protected:

        /// <summary>
        /// Constructor is private. Use static CreateInstance method to instantiate.
        /// </summary>                
        SourceReaderCallback();

        /// <summary>
        // Destructor is private. Caller should call Release.
        /// </summary>
        virtual ~SourceReaderCallback();        

        /// <summary>
        /// Reference count.
        /// </summary> 
        long                    m_lRefCount;

        /// <summary>
        /// MF Source reader which is wrapped by this class
        /// </summary> 
        IMFSourceReader         *m_pReader;

        /// <summary>
        /// Width in pixels
        /// </summary> 
        size_t                   m_width;

        /// <summary>
        /// Height in pixels
        /// </summary> 
        size_t                   m_height;

        /// <summary>
        /// Callback to call to handle read sample completion.
        /// </summary> 
        ReadSampleHandlerForDevice m_readSampleHandler;
    };
}}}}}
